//	--------------------------------------------------------------------
//	Copyright(C) 2006,2007 Zhao Yukun. All rights reserved.
//	This file is a part of the Xeres system.
//	Xeres 2007
//	Contact : xeres.engine@gmail.com
//	$(reservedInfo)
//	$(reservedDeclaration)
//	--------------------------------------------------------------------
///	@file	<CEffect9.cpp>
///	@path	~/src/graphics/dx9/
///	@date	2007/11/15
///	@desc	Effect implementation in DX 9.

#include "config/config.h"

#include "lib/system/thread_debug.h"

#include "graphics/DxHelpers.h"
#include "graphics/dx9/CEffect9.h"
#include "graphics/dx9/CTechnique9.h"
#include "graphics/dx9/CEffectVariable9.h"

namespace xeres {

	IMPL_IOBJECT_CLASS( CEffect9 );

	// ctor
	CEffect9::CEffect9( ID3DXEffect * effect , RefWeak<IEffectPool> pool )
		: m_pEffect( effect )
		, m_pool( pool )
	{
		// generate description
		memset( &m_desc , 0 , sizeof(D3DXEFFECT_DESC) );

		HRESULT hr = m_pEffect->GetDesc( &m_desc );
		if( FAILED(hr) )
		{
			TRACE_ERROR( _S("CEffect9::Construct: Failed to get effect desc: %s.") ,
				d3d_get_err( hr ) );
			FATAL_ABORT( _S("Failed to get effect description.") );
		}
	}

	// dtor
	CEffect9::~CEffect9( void )
	{
		if( m_pEffect )
		{
			UINT rest = m_pEffect->Release();
			if( rest != 0 )
			{
				TRACE_ERROR( _S("CEffect9::DTOR: Invalid ID3DXEffect reference count.") );
				FATAL_ABORT( _S("Invalid ID3DXEffect reference count.") );
			}
		}
	}

	bool CEffect9::OnLostDevice( void )
	{
		TRACK_FUNCTION_SCOPE();
		RUNNING_ON_THREAD( _S("device") );

		if( m_pEffect )
		{
			m_pEffect->OnLostDevice();
		}
		return true;
	}

	bool CEffect9::OnResetDevice( RefWeak<IDevice> device )
	{
		TRACK_FUNCTION_SCOPE();
		RUNNING_ON_THREAD( _S("device") );

		if( m_pEffect )
		{
			m_pEffect->OnResetDevice();
		}
		return true;
	}

	// GetPool
	RefWeak<IEffectPool> CEffect9::GetPool( void )
	{
		return m_pool;
	}

	size_t CEffect9::GetVariableCount( void )
	{
		return (size_t)m_desc.Parameters;
	}

	// internal get variable, create non-existed
	RefPass< IShaderVariable > CEffect9::GetVariable( D3DXHANDLE handle )
	{
		std::map< D3DXHANDLE , RefWeak<IShaderVariable> >::iterator it = m_parameters.find( handle );
		if( it == m_parameters.end() )
		{
			CEffectVariable9 * var = new CEffectVariable9( this , handle );
			m_parameters[ handle ] = var;
			return RefPass<IShaderVariable>( var );
		}
		else
		{
			return RefPass<IShaderVariable>( it->second );
		}
	}

	RefPass< IShaderVariable > CEffect9::GetVariableByIndex( size_t index )
	{
		if( index >= GetVariableCount() )
		{
			TRACE_ERROR( _S("CEffect9::GetVariableByIndex: Variable index exceed boundary.") );
			return NULL;
		}
		D3DXHANDLE handle = m_pEffect->GetParameter( NULL , (UINT)index );
		if( handle == NULL )
			return NULL;
		return GetVariable( handle );
	}

	RefPass< IShaderVariable > CEffect9::GetVariableByName( const AString& name )
	{
		D3DXHANDLE handle = m_pEffect->GetParameterByName( NULL , name.c_str() );
		if( handle == NULL )
		{
			TRACE_ERROR( _S("CEffect9::GetVariableByName: Variable '%S' not found.") , name.c_str() );
			return NULL;
		}
		return GetVariable( handle );
	}

	RefPass< IShaderVariable > CEffect9::GetVariableBySemantic( const AString& semantic )
	{
		D3DXHANDLE handle = m_pEffect->GetParameterBySemantic( NULL , semantic.c_str() );
		if( handle == NULL )
		{
			TRACE_ERROR( _S("CEffect9::GetVariableByName: Variable semantic:'%S' not found.") , semantic.c_str() );
			return NULL;
		}
		return GetVariable( handle );
	}

	void CEffect9::UnusedVariable( RefWeak<IShaderVariable> var )
	{
		RefWeak<CEffectVariable9> v = var;
		m_parameters.erase( v->m_pParam );
	}

	size_t CEffect9::GetTechniqueCount( void )
	{
		return (size_t) m_desc.Techniques;
	}

	// internal get technique, create non-existed
	RefPass< ITechnique > CEffect9::GetTechnique( D3DXHANDLE handle )
	{
		std::map< D3DXHANDLE , RefWeak<ITechnique> >::iterator it = m_techniques.find( handle );
		if( it == m_techniques.end() )
		{
			CTechnique9 * tech = new CTechnique9( this , handle );
			m_techniques[ handle ] = tech;
			return RefPass<ITechnique>( tech );
		}
		else
		{
			return RefPass<ITechnique>( it->second );
		}
	}

	RefPass< ITechnique > CEffect9::GetTechnique( size_t index )
	{
		if( index >= GetTechniqueCount() )
		{
			TRACE_ERROR( _S("CEffect9::GetTechnique: Technique index exceed boundary.") );
			return NULL;
		}
		D3DXHANDLE handle = m_pEffect->GetTechnique( (UINT)index );
		return GetTechnique( handle );
	}

	RefPass< ITechnique > CEffect9::GetTechnique( const AString& name )
	{
		D3DXHANDLE handle = m_pEffect->GetTechniqueByName( name.c_str() );
		return GetTechnique( handle );
	}

	void CEffect9::UnusedTechnique( RefWeak< ITechnique > tech )
	{
		RefWeak<CTechnique9> t = tech;
		m_techniques.erase( t->m_pTechnique );
	}
	// GetEffectInterface
	IUnknown * CEffect9::GetEffectInterface( void )
	{
		return m_pEffect;
	}

} // namespace xeres
